﻿#pragma once
#include "XyNet/Common/Config.h"
#include "XyNet/Common/Id.h"
#include "XyNet/Common/SubjectObserver.h"
#include <boost/asio.hpp>
#include <google/protobuf/stubs/common.h>

namespace XyNet
{
	class RpcBroadcastChannel;
	class RpcSocketChannel;
	class RpcServiceManager;

	/// RPC终端观察者
	class XYNET_API RpcEndpointObserver : public Observer<RpcEndpointObserver>
	{
	public:
		void onSocketChannelException(
			shared_ptr<RpcSocketChannel> socketChannel, int errorCode) {}
	};

	/// RPC终端，可以是客户端或服务端
	class XYNET_API RpcEndpoint : Subject<RpcEndpointObserver>
	{
	public:
		/// rpc服务端配置
		class XYNET_API Config : public InfoConfig
		{
		protected:
			explicit Config(const string& baseFileName = "");

		public:
			/// 自动处理消息
			XYNET_CONFIG_PROPERTY(AutoHandleMessage, bool, true);
			/// 消息超时时间（秒）
			XYNET_CONFIG_CHECK_PROPERTY(MessageTimeout, int, 15, value > 0);
			/// 最大消息包尺寸
			XYNET_CONFIG_CHECK_PROPERTY(MaxMessagePacketSize, int, 102400, value > 0);
			/// 每秒最大消息数量
			XYNET_CONFIG_CHECK_PROPERTY(MaxMessageCountPerSecond, int, 1000, value > 0);
			/// 最大下载速度（字节每秒）
			XYNET_CONFIG_CHECK_PROPERTY(MaxDownloadSpeed, int, 102400, value > 0);
			/// 最大上传速度（字节每秒）
			XYNET_CONFIG_CHECK_PROPERTY(MaxUploadSpeed, int, 102400, value > 0);
			/// 加密级别（3级，对应AES128/ECC256, AES192/ECC384, AES256/ECC512)
			XYNET_CONFIG_CHECK_PROPERTY(EncryptionLevel, int, 1, value > 0 && value <= 3);
		};

		//////////////////////////////////////////////////////////////////////////

	protected:
		RpcEndpoint(const string& name, shared_ptr<Config> config);

	public:
		virtual ~RpcEndpoint();

		/// 获取配置
		shared_ptr<const Config> getConfig() const;
		/// 获取io服务（返回值会被修改，不用const）
		boost::asio::io_service* getIoService();
		/// 获取服务管理器（返回值会被修改，用于添加服务，不能加const）
		shared_ptr<RpcServiceManager> getServiceManager();

		/// 创建套接字通道
		virtual shared_ptr<RpcSocketChannel> createSocketChannel(
			shared_ptr<boost::asio::ip::tcp::socket> socket);
		/// 创建广播通道
		virtual shared_ptr<RpcBroadcastChannel> createBroadcastChannel() = 0;

		/// 查找套接字通道
		virtual shared_ptr<RpcSocketChannel> findSocketChannel(const Id& id) const = 0;

		/// 处理套接字异常（同时断开套接字通道）
		void handleSocketException(shared_ptr<boost::asio::ip::tcp::socket> socket,
			const boost::system::error_code& error,
			shared_ptr<RpcSocketChannel> socketChannel = nullptr);
		/// 处理套接字通道异常
		virtual void handleSocketChannelException(
			shared_ptr<RpcSocketChannel> socketChannel, int errorCode);

		/// 阻塞执行
		void blockRun();

	protected:
		/// 开启线程执行网络服务
		void run(int concurrency);
		/// 停止网络服务
		void stop();

	private:
		/// 名称
		const string _name;
		/// 配置
		shared_ptr<Config> _config;

		/// asio服务
		boost::asio::io_service _ioService;
		/// 网络服务线程
		vector<shared_ptr<thread>> _ioServiceThreads;

		/// 服务管理器
		shared_ptr<RpcServiceManager> _serviceManager;
	};

	//////////////////////////////////////////////////////////////////////////

	/// 负责清理google分配的内存
	class ProtobufCleaner
	{
	public:
		~ProtobufCleaner()
		{
			google::protobuf::ShutdownProtobufLibrary();
		}
	} static _protobufCleaner;
}